#!/usr/bin/env python
#-*- encoding=utf8 -*-
import os
import sys
import redis

DATPATH = 'dat/'
LOCPATH = DATPATH+ 'loc/'
RAWSUFFIX = '.rfp'
RMPSUFFIX = '.rmp'
LOCSUFFIX = '.loc'

ENV_PRODUCT = True
#ENV_PRODUCT = False

#DEBUG_ALGO = True
DEBUG_ALGO = False

CLUSTERKEYSIZE = 8
KNN = 10
KWIN = 1.25

RADIUS = 6372797  # meter
MAX_AREA_TRY = 200
CRAWL_LIMIT = 5000

GOOG_AVAIL = True
GOOG_ERR_LIMIT = 300
GOOG_FAIL_LIMIT = 25
GOOG_FAIL_CACHE_TIME = 3600*24

IP_CACHE_REDIS = '192.168.109.56'
PORT_CACHE_REDIS = 6379

# CSV formats.
csv_fmt_indoorfp = ['iac', 'h', 'building_id', 'time', 'macs', 'rsss']

# Raw FP CSV column config.
CSV_CFG_RFP = {
    14 : { 'lat'  : 8, 
           'lon'  : 9, 
           'h'    : 10,
           'macs' : 11, 
           'rsss' : 12,
           'time' : 13, },
    16 : { 'lat'  : 11, 
           'lon'  : 12, 
           'h'    : 13,
           'macs' : 14, 
           'rsss' : 15,
           'time' : 2, },
     6 : { 'iac'  : 0, 
           'h'    : 1,
           'bid'  : 2,
           'time' : 3, 
           'macs' : 4, 
           'rsss' : 5, },
}
FP_FIELD_NAMES = {
    'outdoor' : [ 'lat', 'lon', 'h', 'rsss', 'time' ],
     'indoor' : [ 'iac', 'h', 'bid', 'time', 'rsss' ]
}

# Logging related cfg.
from logging import getLogger, Formatter, INFO, DEBUG
from cloghandler import ConcurrentRotatingFileHandler as cLogRotateFileHandler
#WPPLOG_FMT = '[%(asctime)s][P:%(process)s][%(levelname)s] %(message)s'  # Outdoor.
WPPLOG_FMT = '[%(asctime)s][%(levelname)s] %(message)s'                  # Indoor.
#WPPLOG_FILE = 'wpp.log'        # Outdoor.
WPPLOG_FILE = 'wpp_indoor.log'  # Indoor.
wpplog = getLogger('wpp')
wpplog.setLevel(DEBUG)
logfmt = Formatter(WPPLOG_FMT)
logdir = '%s/tmp/log' % os.environ['HOME']
logfile = '%s/%s' % (logdir, WPPLOG_FILE)
if not os.path.isfile(logfile):
    if not os.path.isdir(logdir):
        try:
            os.mkdir(logdir, 0755)
        except OSError, errmsg:
            print "Failed to mkdir: %s, %s!" % (logdir, str(errmsg))
            sys.exit(99)
    open(logfile, 'w').close()
loghandler = cLogRotateFileHandler(logfile, "a", 30*1024*1024, 200) # Rotate after 30M, keep 200 old copies.
loghandler.setFormatter(logfmt)
wpplog.addHandler(loghandler)

mc = redis.Redis(host=IP_CACHE_REDIS, port=PORT_CACHE_REDIS, db=0)

# PosResp msg fmt.
POS_RESP_FULL="""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE PosRes SYSTEM "PosRes.dtd">
<PosRes>
        <Result ErrCode="%s" ErrDesc="%s"/>
        <Coord lat="%s" lon="%s" h="0.0"/>
        <ErrRange val="%s"/>
        <PosLevel val="%s" />
        <Area code="%s" addr="%s"/>
</PosRes>"""
POS_RESP_PT="""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE PosRes SYSTEM "PosRes.dtd">
<PosRes>
        <Result ErrCode="%s" ErrDesc="%s"/>
        <Coord lat="%s" lon="%s" h="0.0"/>
        <ErrRange val="%s"/>
        <PosLevel val="%s" />
</PosRes>"""
POS_RESP_AREA="""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE PosRes SYSTEM "PosRes.dtd">
<PosRes>
        <Result ErrCode="%s" ErrDesc="%s"/>
        <PosLevel val="%s" />
        <Area code="%s" addr="%s"/>
</PosRes>"""
POS_RESP_INDOOR="""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE PosRes SYSTEM "PosRes.dtd">
<PosRes>
        <Result ErrCode="%s" ErrDesc="%s"/>
        <Coord iac="%s" h="%s" bid="%s"/>
        <ErrRange val="5"/>
        <PosLevel val="Point" />
</PosRes>"""
XHTML_IMT = "application/xhtml+xml"

# FPP-WPP rawdata sync related.
ftpcfgs = { 
  'fpp_neu_ln': {
       'user' : 'fpp',
     'passwd' : '123fpp!@#',
          'ip': '10.64.74.33',
        'port': 21,
        'path': 'fpp/data_sync/wpp',
     'timeout': 20,
    'localdir': '/opt/projs/cmri/wpp/src/wpp/dat/sync'},
'fpp_neu_cmri': {
       'user' : 'fpp',
     'passwd' : 'fpp',
          'ip': '192.168.109.58',
        'port': 21,
        'path': 'fpp/data_sync/wpp',
     'timeout': 20,
    'localdir': '/opt/wpp/src/wpp/dat/sync'},
  'local': {
       'user' : 'alexy',
     'passwd' : 'yan714257',
          'ip': 'localhost',
        'port': 21,
        'path': 'tmp/wpp/ftp',
     'timeout': 10,
    'localdir': '/home/alexy/tmp/wpp/local'},
}
FTPCFG = ftpcfgs['fpp_neu_cmri']
mailcfg = {
      'from' : 'xiaotian.yan@gmail.com',
       'to'  : '13811310350@139.com',
    'userpwd': ('xiaotian.yan','yan714257'),
}
errmsg = { 'db' : """
TABLE: [%s]
OPERATION: [%s]
DETAILS: %s

--
WPP@%s
%s""",
}
# DB related configuration.
DB_CFG = {
    'wpp_cmri': {
        'online' : '192.168.109.54',
        'offline' : ( '192.168.109.54', ),
        'upload' : ( '192.168.109.54', ),
    },
    'wpp_local': {
        'online' : 'local_pg',
        'offline' : ( 'local_pg', ),
        'upload' : ( 'local_pg', ),
    },
    'wpp_cmri_indoor': {
        'online' : 'cmri_pg_indoor',
        'offline' : ( 'cmri_pg_indoor', ),
        'upload' : ( 'cmri_pg_indoor', ),
    },
    'wpp_local_indoor': {
        'online' : 'local_pg_indoor',
        'offline' : ( 'local_pg_indoor', ),
        'upload' : ( 'local_pg_indoor', ),
    },
}
#DB = DB_CFG['wpp_local']
DB = DB_CFG['wpp_cmri_indoor'] if ENV_PRODUCT else DB_CFG['wpp_local_indoor']
DB_ONLINE  = DB['online']
DB_OFFLINE = DB['offline']
DB_UPLOAD  = DB['upload']
# dsn config.
dsn_local_pg = "host=localhost dbname=wppdb user=wpp password=wpp port=5432"
dsn_local_pg_indoor = "host=localhost dbname=wppdb_indoor user=wpp password=wpp port=5432"
dsn_cmri_pg_indoor = "host=192.168.109.54 dbname=wppdb_indoor user=wpp password=wpp port=5432"
dsn_cmri_pg = "host=192.168.109.54 dbname=wppdb user=wpp password=wpp port=5432"
#dsn_vance_pg = "host=192.168.109.49 dbname=wppdb user=mwlan password=mwlan_pw port=5432"
#dsn_local_ora = "yxt/yxt@localhost:1521/XE"
#dsn_vance_ora = "mwlan/mwlan_pw@192.168.35.202/wlandb"
#dsn_vance_pg_mic = "host=192.168.19.132 dbname=wpp user=mwlan password=mwlan_pw port=5432"
#dbtype_ora = 'oracle' 
#dbtype_my  = 'mysql'
dbtype_pg  = 'postgresql'
dbsvrs = {
          '192.168.109.54':{
            'dsn':dsn_cmri_pg,
            'dbtype':dbtype_pg,
           },
          'local_pg':{
            'dsn':dsn_local_pg,
            'dbtype':dbtype_pg,
           },
          'cmri_pg_indoor':{
            'dsn':dsn_cmri_pg_indoor,
            'dbtype':dbtype_pg,
           },
          'local_pg_indoor':{
            'dsn':dsn_local_pg_indoor,
            'dbtype':dbtype_pg,
           },
          #'192.168.109.49':{
          #  'dsn':dsn_vance_pg,
          #  'dbtype':dbtype_pg,
          # },
          #'local_ora':{
          #  'dsn':dsn_local_ora,
          #  'dbtype':dbtype_ora,
          # },
        }
# IAC graph data.
# bid: { floor: { 'iac1': {'range': 5, 'nexthops': ['iac11','iac12',...] }, }, }
iac_graph = {
  2: { # Innovation building.
    19: { # Service tech department.
      '1.1.1' : { 'r': 5, 'n': [ '1.1.2',  '1.1.9',  '1.4.2', '1.4.1' ], },
      '1.1.2' : { 'r': 5, 'n': [ '1.1.10', '1.1.1',  '1.1.3' ], },
      '1.1.3' : { 'r': 5, 'n': [ '1.1.11', '1.1.2',  '1.1.4' ], },
      '1.1.4' : { 'r': 5, 'n': [ '1.1.12', '1.1.3',  '1.1.5' ], },
      '1.1.5' : { 'r': 5, 'n': [ '1.1.13', '1.1.4',  '1.1.6' ], },
      '1.1.6' : { 'r': 5, 'n': [ '1.1.14', '1.1.5',  '1.1.7' ], },
      '1.1.7' : { 'r': 5, 'n': [ '1.1.15', '1.1.6',  '1.1.8' ], },
      '1.1.8' : { 'r': 5, 'n': [ '1.1.16', '1.5.2',  '1.5.1', '1.1.7' ], },
      '1.1.9' : { 'r': 5, 'n': [ '1.1.1',  '1.1.19', '1.4.2', '1.4.3' ], },
      '1.1.10': { 'r': 5, 'n': [ '1.1.2',  '1.1.11' ], },
      '1.1.11': { 'r': 5, 'n': [ '1.1.3',  '1.1.12', '1.1.11','2.1.3' ], },
      '1.1.12': { 'r': 5, 'n': [ '1.1.4',  '1.1.11', '2.1.3' ], },
      '1.1.13': { 'r': 5, 'n': [ '1.1.5',  '2.1.4',  '2.1.3' ], },
      '1.1.14': { 'r': 5, 'n': [ '1.1.6',  '2.1.5',  '2.1.4' ], },
      '1.1.15': { 'r': 5, 'n': [ '1.1.7',  '2.1.5',  '1.6.1' ], },
      '1.1.16': { 'r': 5, 'n': [ '1.1.8',  '1.5.2',  '1.6.1', '1.5.3' ], },
      '1.1.19': { 'r': 5, 'n': [ '1.1.9',  '2.1.2',  '1.4.3' ], }, # FIXME: add 2.4.1
      '2.1.2':  { 'r': 5, 'n': [ '1.1.19', '2.1.3',  '2.1.7' ], },
      '2.1.3':  { 'r': 5, 'n': [ '1.1.12', '1.1.13', '2.1.2', '2.1.4', '2.2.1' ], },
      '2.1.4':  { 'r': 5, 'n': [ '1.1.13', '1.1.14', '2.1.3', '2.1.5', '2.2.1' ], },
      '2.1.5':  { 'r': 5, 'n': [ '1.1.14', '1.1.15', '2.1.4', '1.6.1', '2.3.1' ], },
      '2.2.1':  { 'r': 5, 'n': [ '2.1.3',  '2.2.2',  '2.2.3', '2.2.5' ], },
      '2.2.2':  { 'r': 5, 'n': [ '2.2.2',  '2.2.3',  '2.2.5' ], },
      '2.2.3':  { 'r': 5, 'n': [ '2.2.1',  '2.2.2',  '2.2.4', '2.2.5' ], },
      '2.2.4':  { 'r': 5, 'n': [ '2.2.3',  '2.2.1' ], },
      '2.2.5':  { 'r': 5, 'n': [ '2.2.3',  '1.8.1',  '1.8.2' ], },
      '2.3.1':  { 'r': 5, 'n': [ '2.3.2',  '2.1.5' ], },
      '2.3.2':  { 'r': 5, 'n': [ '2.3.1',  '1.6.3',  '2.3.3' ], },
      '2.3.3':  { 'r': 5, 'n': [ '2.3.2',  '1.6.4' ], }, # FIXME: to be modified: 1.6.4
      '1.6.1':  { 'r': 5, 'n': [ '1.1.15', '1.1.16', '2.1.5', '2.3.1', '2.5.1', '1.5.3', '1.5.4' ], },
      '1.6.3':  { 'r': 5, 'n': [ '2.3.2' ], },
      '1.6.4':  { 'r': 5, 'n': [ '2.3.3',  '2.5.3' ], }, # FIXME: 2.5.3, 2.3.3
      '2.5.1':  { 'r': 5, 'n': [ '1.6.1',  '1.3.1',  '2.5.2' ], },
      '2.5.2':  { 'r': 5, 'n': [ '2.5.1',  '1.3.3',  '2.5.3' ], },
      '2.5.3':  { 'r': 5, 'n': [ '2.5.2',  '1.3.5',  '1.6.4', '1.11.4' ], }, # FIXME: 1.6.4
      '1.3.1':  { 'r': 5, 'n': [ '2.5.1',  '1.3.2' ], },
      '1.3.2':  { 'r': 5, 'n': [ '1.3.1',  '1.3.4' ], },
      '1.3.3':  { 'r': 5, 'n': [ '1.3.4',  '2.5.2' ], },
      '1.3.4':  { 'r': 5, 'n': [ '1.3.3',  '1.3.2',  '1.3.6' ], },
      '1.3.5':  { 'r': 5, 'n': [ '1.3.6',  '2.5.3' ], },
      '1.3.6':  { 'r': 5, 'n': [ '1.3.5',  '1.3.4' ], },
      '1.4.1':  { 'r': 5, 'n': [ '1.1.1',  '1.4.2' ], },
      '1.4.2':  { 'r': 5, 'n': [ '1.4.1',  '1.1.1',  '1.1.9', '1.1.19' ], },
      '1.4.3':  { 'r': 5, 'n': [ '1.4.2',  '1.1.19', '1.1.9' ], },
      '1.8.1':  { 'r': 5, 'n': [ '2.2.5' ], },
      '1.8.2':  { 'r': 5, 'n': [ '2.2.5' ], },
      '1.11.4': { 'r': 5, 'n': [ '2.5.3',  '1.6.4' ], },
      '1.5.1':  { 'r': 5, 'n': [ '1.1.8',  '1.5.2' ], },
      '1.5.2':  { 'r': 5, 'n': [ '1.1.8',  '1.5.1',  '1.1.16','1.5.3' ], },
      '1.5.3':  { 'r': 5, 'n': [ '1.1.16', '1.5.2',  '1.6.1' ], },
      '1.5.4':  { 'r': 5, 'n': [ '2.5.1',  '1.6.1' ], },
      '2.4.1':  { 'r': 5, 'n': [ '1.1.19', '1.2.14', '1.2.4', '2.4.2' ], },
    },
  },
}
# { table_name: table_instance }
wpp_tables = { 'wpp_clusteridaps':'wpp_clusteridaps',
                       'wpp_cfps':'wpp_cfps',
                 'wpp_uprecsinfo':'wpp_uprecsinfo',
                  'wpp_uprecsver':'wpp_uprecsver',
                     'wpp_celloc':'wpp_celloc',
                   'wpp_cellarea':'wpp_cellarea',
               'wpp_uprecs_noloc':'wpp_uprecs_noloc' }
# NOTE: tbl_fields dont contain PRIMAY key or SERIAL columns, like *id* in wpp_uprecsinfo.
tbl_field = { 'wpp_clusteridaps':('clusterid', 'keyaps', 'seq'),
                      'wpp_cfps':('clusterid', 'lat', 'lon', 'height', 'rsss', 'cfps_time'),
                'wpp_uprecsinfo':('spid','servid','time','imsi','imei','useragent',
                                  'mcc','mnc','lac','cellid','cellrss',
                                  'lat','lon','height','wlanidentifier','wlanmatcher',
                                  'ver_uprecs', 'area_ok', 'area_try'),
              'wpp_uprecs_noloc':('spid','servid','time','imsi','imei','useragent',
                                  'mcc','mnc','lac','cellid','cellrss',
                                  'lat','lon','height','wlanidentifier','wlanmatcher',
                                  'ver_uprecs'),
                    'wpp_celloc':('laccid', 'lat', 'lon', 'h', 'ee'),
                  'wpp_cellarea':('laccid', 'areacode', 'areaname'),
                        'tsttbl':('clusterid', 'keyaps', 'seq') }
tbl_idx =   { 'wpp_clusteridaps':('clusterid','keyaps'), #{table_name:{'field_name'}}
                      'wpp_cfps':('clusterid',),
                'wpp_uprecsinfo':('ver_uprecs','area_ok'),
              'wpp_uprecs_noloc':('ver_uprecs',),
                    'wpp_celloc':('laccid',),
                  'wpp_cellarea':('laccid',),
                 'wpp_uprecsver':(),
                        'tsttbl':('clusterid',)}
tbl_files = { 'wpp_clusteridaps':'test/tbl/cidaps.tbl', 
                      'wpp_cfps':'test/tbl/cfprints.tbl',
                'wpp_uprecsinfo':'test/tbl/uprecs.tbl',
              'wpp_uprecs_noloc':'test/tbl/uprecs_noloc.tbl',
                 'wpp_uprecsver':'test/tbl/uprecsver.tbl',
                        'cidaps':'test/tbl/cidaps.tbl',
                          'cfps':'test/tbl/cfprints.tbl',
                    'wpp_celloc':'test/tbl/celloc.tbl',
                  'wpp_cellarea':'test/tbl/cellarea.tbl',
                        'tsttbl':'test/tbl/tsttbl.tbl' }
tbl_forms = { 
              'postgresql':{
                'wpp_clusteridaps':"""(
                     clusterid INT NOT NULL, 
                        keyaps VARCHAR(360) NOT NULL,
                           seq INT NOT NULL)""", 
                'wpp_cfps':""" (
                     clusterid INT NOT NULL,
                           lat NUMERIC(9,6) NOT NULL,
                           lon NUMERIC(9,6) NOT NULL,
                        height NUMERIC(5,1) DEFAULT 0,
                          rsss VARCHAR(100) NOT NULL,
                     cfps_time VARCHAR(20))""",
                'wpp_cellarea':""" (
                        laccid VARCHAR(30) NOT NULL,
                      areacode VARCHAR(10) NOT NULL,
                      areaname VARCHAR(50) NOT NULL)""",
                'wpp_celloc':""" (
                        laccid VARCHAR(30) NOT NULL,
                           lat NUMERIC(9,6) NOT NULL DEFAULT 0,
                           lon NUMERIC(9,6) NOT NULL DEFAULT 0,
                             h NUMERIC(5,1) DEFAULT 0,
                            ee NUMERIC(5,1) DEFAULT 0)""",
                'wpp_uprecsver':""" (
                    ver_uprecs INT DEFAULT 0)""",
                'wpp_uprecsinfo':""" (
                          spid INT,
                        servid INT,
                          time VARCHAR(20),
                          imsi VARCHAR(20),
                          imei VARCHAR(20),
                     useragent VARCHAR(300),
                           mcc INT DEFAULT 0,
                           mnc INT DEFAULT 0,
                           lac INT DEFAULT 0,
                        cellid INT DEFAULT 0,
                       cellrss VARCHAR(5),
                           lat NUMERIC(9,6) DEFAULT 0,
                           lon NUMERIC(9,6) DEFAULT 0,
                        height NUMERIC(5,1) DEFAULT 0,
                wlanidentifier VARCHAR(1024),
                   wlanmatcher VARCHAR(255),
                    ver_uprecs INT DEFAULT 0),
                       area_ok SMALLINT DEFAULT 0),
                      area_try INT DEFAULT 0)""",
                'wpp_uprecs_noloc':""" (
                          spid INT,
                        servid INT,
                          time VARCHAR(20),
                          imsi VARCHAR(20),
                          imei VARCHAR(20),
                     useragent VARCHAR(300),
                           mcc INT DEFAULT 0,
                           mnc INT DEFAULT 0,
                           lac INT DEFAULT 0,
                        cellid INT DEFAULT 0,
                       cellrss VARCHAR(5),
                           lat NUMERIC(9,6) DEFAULT 0,
                           lon NUMERIC(9,6) DEFAULT 0,
                        height NUMERIC(5,1) DEFAULT 0,
                wlanidentifier VARCHAR(1024),
                   wlanmatcher VARCHAR(255),
                    ver_uprecs INT DEFAULT 0)""",
                'tsttbl':"""(
                     clusterid INT, 
                        keyaps VARCHAR2(71) NOT NULL,
                           seq INT NOT NULL)""" }}
# SQL statements.
sqls = { 'SQL_SELECT' : "SELECT %s FROM %s",
         'SQL_UPDATE' : "UPDATE %s SET %s = %s",
         'SQL_DELETE' : "DELETE FROM %s WHERE %s",
         'SQL_DROPTB' : "DROP TABLE %s PURGE",
      'SQL_DROPTB_IE' : "DROP TABLE IF EXISTS %s",
         'SQL_INSERT' : "INSERT INTO %s %s VALUES %s",
  'SQL_INSERT_SELECT' : "INSERT INTO %s SELECT %s FROM %s",
        'SQL_TRUNCTB' : "TRUNCATE TABLE %s",
        'SQL_DROP_MY' : "DROP TABLE IF EXISTS %s",
       'SQL_DROP_IDX' : "DROP INDEX %s",
    'SQL_DROP_IDX_IE' : "DROP INDEX IF EXISTS %s",
       'SQL_CREATETB' : "CREATE TABLE %s %s",
      'SQL_CREATEIDX' : "CREATE INDEX %s ON %s(%s)",
     'SQL_CREATEUIDX' : "CREATE UNIQUE INDEX %s ON %s(%s)",
    'SQL_CREATETB_MY' : "CREATE TABLE IF NOT EXISTS %s %s",
       'SQL_CSVIN_MY' : """
                        LOAD DATA LOCAL INFILE "%s" INTO TABLE %s 
                        FIELDS TERMINATED BY ',' 
                        LINES TERMINATED BY '\\n' 
                        %s""" }

# Test input csv file
TESTFILE = os.path.dirname(__file__) + '/../dat/test.csv'
# Text colors
termtxtcolors = {
        'red':'\033[91m%s\033[0m',
      'green':'\033[92m%s\033[0m',
     'yellow':'\033[93m%s\033[0m',
       'blue':'\033[94m%s\033[0m',
     'purple':'\033[95m%s\033[0m'
}
# String length of 179 and 149 chars are used for each intersection set to have 
# at most INTERSET APs, which should be enough for classification, very ugly though.
#dt_rmp_nocluster = {'names':('spid','lat','lon','macs','rsss'), 
#                  'formats':('i4','f4','f4','S179','S149')}
WLAN_FAKE = {
        36: # Indoor: cluster #6, full match, 3 fps.
            [ ['5C:63:BF:62:6D:32', '-28'], ['54:E6:FC:1F:DD:02', '-66'],
              ['5C:63:BF:A8:D7:56', '-70'], ['F4:EC:38:22:5F:7E', '-81'] ],
        37: # Indoor: cluster #8, full match, 1 fps.
            [ ['5C:63:BF:62:6D:32', '-28'], ['54:E6:FC:1F:DD:02', '-66'],
              ['5C:63:BF:A8:D7:56', '-70'], ['B0:48:7A:66:8B:6A', '-77'] ],
        38: # Indoor: cluster #2, #6, #8, part match(3), 34 fps.
            [ ['5C:63:BF:62:6D:32', '-28'], ['54:E6:FC:1F:DD:02', '-66'],
              ['5C:63:BF:A8:D7:56', '-70'], ],
        39: # Indoor
            [ ['00:11:b5:fd:8e:f6', '-28'], ['38:83:45:6a:55:2c', '-66'],
              ['d2:73:56:c0:ea:7d', '-70'], ],

            
}
#icon_types = { 'on': [ '"encrypton"',  '/kml/icons/encrypton.png'],
#              'off': [ '"encryptoff"', '/kml/icons/encryptoff.png'],
#           'reddot': [ '"reddot"',     '/kml/icons/reddot.png'],
#          'bluedot': [ '"bluedot"',    '/kml/icons/bluedot.png'],
#        'yellowdot': [ '"yellowdot"',  '/kml/icons/yellowdot.png'],
#             'wifi': [ '"wifi"',       '/kml/icons/wifi.png'],
#        'dotshadow': [ '"dotshadow"',  '/kml/icons/dotshadow.png'],
#}


if __name__ == '__main__':
    import pprint as pp
    def search_cands(iac=None, bid=2, floor=19):
        cands = set()
        ig_f19 = iac_graph[bid][floor]
        next_hops = ig_f19[iac]['n'] 
        for node in next_hops:
            cands = cands.union( set(ig_f19[node]['n']) )
        return cands.union(set(next_hops))
    iac = '1.6.3'
    print 'Candidate IACs around %s:' % iac
    pp.pprint(search_cands(iac))
